package com.googlecode.gwtbb.server.intermediate.search.forum;

import com.googlecode.gwtbb.client.shared.entity.forum.Post;
import com.googlecode.gwtbb.client.shared.remote.search.SearchResults;
import com.googlecode.gwtbb.client.shared.util.StringUtils;
import com.googlecode.gwtbb.server.intermediate.search.DirectorySearcher;
import org.apache.commons.collections.map.Flat3Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.lucene.document.Document;
import org.apache.lucene.queryParser.MultiFieldQueryParser;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.Hits;
import org.apache.lucene.search.Query;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.Map;

/**
 * @author Abraham Grief
 * @version $Id$
 * @since Jul 29, 2008
 */
public class PostSearcher extends DirectorySearcher {
	private static Log log = LogFactory.getLog(PostSearcher.class);
	private ThreadLocal<QueryParser> postQueryParser;

	@Override
	public synchronized void init() throws IOException {
		super.init();
		postQueryParser = new ThreadLocal<QueryParser>() {
			@Override
			protected QueryParser initialValue() {
				//noinspection unchecked
				Map<String, Float> boosts = new Flat3Map();
				boosts.put(Post.SUBJECT, new Float(1.5));
				boosts.put(Post.BODY, new Float(1.0));
				return new MultiFieldQueryParser(new String[]{Post.SUBJECT, Post.BODY}, getAnalyzer(), boosts);
			}
		};
	}

	public SearchResults<Post> search(SearchResults<Post> results, String queryString, int maxNumResults) throws ParseException, IOException {
		results.setResults(new ArrayList<Post>(maxNumResults));
		results.setQueryString(queryString);
		if (StringUtils.isNotEmpty(queryString)) {
			try {
				doSearch(results);
			} catch (IOException e) {
				log.info("possibly closed searcher during search");
				results.getResults().clear();
				doSearch(results);
			}
		}
		return results;
	}

	private Post createResult(Document doc) {
		return new Post(Long.valueOf(doc.get(Post.ID)), Long.valueOf(doc.get(Post.THREAD_ID)), Long.valueOf(doc.get(Post.FORUM_ID)), Long.valueOf(doc.get(Post.USER_ID)), doc.get(Post.SUBJECT), doc.get(Post.BODY), new Date(Long.parseLong(doc.get(Post.SNAP_DATE))), new Date(Long.parseLong(doc.get(Post.SNAP_DATE))));
	}

	private void doSearch(SearchResults<Post> searchResults) throws IOException, ParseException {
		Query query = postQueryParser.get().parse(searchResults.getQueryString());
		Hits hits = getSearcher().search(query);
		int numResults = Math.min(hits.length(), searchResults.getMaxNumResults());
		for (int i = 0; i < numResults; i++)
			searchResults.getResults().add(createResult(hits.doc(i)));
	}
}
